package mqtt2lora

import (
	"encoding/base64"
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commConfig"
	"gitee.com/fierce_wolf/go-fox-edge-common/commLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commMqtt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/ChanSyncObj"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Hex"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Json"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Uuid"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/periodTask"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEnv"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"strings"
)

type mqttClient struct {
	client *commMqtt.MqttClient
	fmts   []*mqttMsgFmt
}

type mqttMsgFmt struct {
	devEUIKey        string
	dataKey          string
	dataFmt          string
	gatewayEUIPrefix string
	gatewayEUISuffix string
}

func (e *mqttClient) GetDefaultHandler() mqtt.MessageHandler {
	return func(client mqtt.Client, msg mqtt.Message) {
		fmt.Printf("TOPIC: %s\n", msg.Topic())
		fmt.Printf("MSG: %s\n", msg.Payload())
	}
}

func (e *mqttClient) instance() {
	// 初始化mqtt的连接
	err := e.instanceMqtt()
	if err != nil {
		commLogger.Error(err.Error())
		return
	}

	// 初始化消息格式的解析配置
	err = e.instanceMsgFmts()
	if err != nil {
		commLogger.Error(err.Error())
		return
	}

	return
}

func (e *mqttClient) instanceMqtt() (err error) {
	defer func() {
		if e := recover(); e != nil {
			message := fmt.Sprintf("解析全局配置serverConfig 失败:%v", e)
			err = errors.New(message)
		}
	}()

	// 获得系统配置参数
	configValue, err := commConfig.GetConfigParam("serverConfig")
	if err != nil {
		return fmt.Errorf("mqtt参数初始化失败：找不到serverConfig配置项")
	}

	// 取出系统配置参数
	mqtt := Map.GetMap(configValue, "mqtt", make(map[string]interface{}))
	topics := Map.GetMap(configValue, "topic", make(map[string]interface{}))

	if mqtt == nil || topics == nil {
		return fmt.Errorf("mqtt参数初始化失败")
	}

	clientId := Map.GetString(mqtt, "clientId", "")
	if clientId == "" {
		clientId = Uuid.RandomUUID()
	}

	uplink := Map.GetString(topics, "uplink", "")
	downlink := Map.GetString(topics, "downlink", "")
	if uplink == "" || downlink == "" {
		return nil
	}

	// 设置MQTT的通信参数
	client := commMqtt.NewClient(clientId)
	client.SetOption(mqtt)
	e.client = client

	// 向MQTT BROKER注册订阅topic
	Handler.clientId = clientId
	Handler.topic = downlink
	e.client.Subscribe(uplink, Handler.Handler())

	periodTask.InsertTask(commMqtt.AutoTask)
	periodTask.Scheduler()

	return nil
}

func (e *mqttClient) instanceMsgFmts() (err error) {
	// 拦截可能产生的异常
	defer func() {
		if e := recover(); e != nil {
			message := fmt.Sprintf("解析全局配置serverConfig 失败:%v", e)
			err = errors.New(message)
		}
	}()

	configValue, err := commConfig.GetConfigParam("serverConfig")
	if err != nil {
		return err
	}

	message := Map.GetSlice(configValue, "message", make([]interface{}, 0))
	for _, val := range message {
		gatewayEUI := Map.GetMap(val.(map[string]interface{}), "gatewayEUI", make(map[string]interface{}))
		devEUI := Map.GetMap(val.(map[string]interface{}), "devEUI", make(map[string]interface{}))
		data := Map.GetMap(val.(map[string]interface{}), "data", make(map[string]interface{}))

		gatewayEUITopic := Map.GetString(gatewayEUI, "topic", "")
		devEUIKey := Map.GetString(devEUI, "key", "")

		dataKey := Map.GetString(data, "key", "")
		dataFmt := Map.GetString(data, "fmt", "")

		mqttMsg := &mqttMsgFmt{}
		mqttMsg.devEUIKey = devEUIKey
		mqttMsg.dataKey = dataKey
		mqttMsg.dataFmt = dataFmt

		gatewayEUITopicIndex := strings.Index(gatewayEUITopic, "{gatewayEUI}")
		if gatewayEUITopicIndex >= 0 {
			mqttMsg.gatewayEUIPrefix = gatewayEUITopic[:gatewayEUITopicIndex]
			mqttMsg.gatewayEUISuffix = gatewayEUITopic[gatewayEUITopicIndex+len("{gatewayEUI}"):]
		}

		e.fmts = append(e.fmts, mqttMsg)
	}

	return nil
}

func (e *mqttClient) GetMqttClient() *commMqtt.MqttClient {
	return e.client
}

func (e *mqttClient) GetTopicDownlink() (string, error) {
	// 获得系统配置参数
	configValue, err := commConfig.GetConfigParam("serverConfig")
	if err != nil {
		return "", err
	}

	// 取出系统配置参数
	topics := Map.GetMap(configValue, "topic", make(map[string]interface{}))
	if topics == nil {
		return "", errors.New("配置参数缺失：topic")
	}

	downlink := Map.GetString(topics, "downlink", "")
	if downlink == "" {
		return "", errors.New("配置参数缺失：topic下缺失downlink")
	}
	downlink = strings.ReplaceAll(downlink, "{gatewayEui}", edgeEnv.GetCPUID())

	return downlink, nil
}

func (e *mqttClient) Request(devEUI string, fport int, request string, timeout int) (interface{}, error) {
	// 取出mqtt的client，用来发送数据
	if e.client == nil || !e.client.IsConnected() {
		return nil, errors.New("mqtt客户端，尚未与mqtt broker建立链接：")
	}

	// 从全局配置中，取出下行的topic
	topic, err := e.GetTopicDownlink()
	if err != nil {
		return nil, err
	}
	topic = strings.ReplaceAll(topic, "$deveui", devEUI)

	// HEX数据转换成PDU
	pdu := Hex.DecodeString(request)
	if len(pdu) == 0 {
		return nil, errors.New("发送数据的格式不正确：" + request)
	}

	// body的数据
	body := make(map[string]interface{})
	body["devEUI"] = devEUI
	body["confirmed"] = true
	body["fport"] = fport
	body["data"] = base64.StdEncoding.EncodeToString(Hex.DecodeString(request))
	json := Json.BuildJson(body)

	// 推送数据给mqtt broker
	if !e.client.Publish(topic, json, 5*000) {
		return nil, errors.New("推送数据到mqtt broker失败")
	}

	// 等到lora子设备的数据，通过lora网关，推送到mqtt broker
	recv := ChanSyncObj.Wait(devEUI, int64(timeout+1*000))
	if recv == nil {
		return nil, errors.New("没有接收到设备的数据")
	}

	return recv, nil
}
